/*
* Author: honrun
*/
#include "n32g031.h"
#include "stdint.h"
#include "stdio.h"
#include "string.h"
#include "DevicesUart.h"


uint8_t g_USART1ReadDMABuff[USART1_DMA_READ_LENGTH + 4] = {0};
uint8_t g_USART1SendDMABuff[USART1_DMA_SEND_LENGTH + 4] = {0};
uint8_t g_USART2ReadDMABuff[USART2_DMA_READ_LENGTH + 4] = {0};
uint8_t g_USART2SendDMABuff[USART2_DMA_SEND_LENGTH + 4] = {0};



void vUart1Init(void)
{
    GPIO_InitType GPIO_InitStructure = {0};
    USART_InitType USART_InitStructure = {0};
    NVIC_InitType NVIC_InitStructure = {0};


    /* Enable GPIO clock */
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
    /* Enable USARTx Clock */
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_USART1, ENABLE);


    /* Configure USARTy Tx as alternate function push-pull */
    GPIO_InitStructure.Pin            = GPIO_PIN_9;
    GPIO_InitStructure.GPIO_Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF4_USART1;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);

    /* Configure USARTx Rx as alternate function push-pull */
    GPIO_InitStructure.Pin            = GPIO_PIN_10;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);


    /* USARTx configuration ------------------------------------------------------*/
    USART_InitStructure.BaudRate            = 115200;
    USART_InitStructure.WordLength          = USART_WL_8B;
    USART_InitStructure.StopBits            = USART_STPB_1;
    USART_InitStructure.Parity              = USART_PE_NO;
    USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
    USART_InitStructure.Mode                = USART_MODE_RX | USART_MODE_TX;
    USART_Init(USART1, &USART_InitStructure);


    vUart1DMAInit();


    /* Enable the USARTx Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel            = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority    = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd         = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* Enable USARTx IDLE interrupts */
    USART_ConfigInt(USART1, USART_INT_IDLEF, ENABLE);


    /* Enable the USARTx */
    USART_Enable(USART1, ENABLE);
}

void vUart1DMAInit(void)
{
    DMA_InitType DMA_InitStructure = {0};


    /* DMA clock enable */
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE);


    /* USARTy TX DMA Channel (triggered by USARTy Tx event) Config */
    DMA_DeInit(DMA_CH4);
    DMA_InitStructure.PeriphAddr     = (USART1_BASE + 0x04);
    DMA_InitStructure.MemAddr        = (uint32_t)g_USART1SendDMABuff;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_DST;
    DMA_InitStructure.BufSize        = USART1_DMA_SEND_LENGTH;
    DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
    DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.CircularMode   = DMA_MODE_NORMAL;
    DMA_InitStructure.Priority       = DMA_PRIORITY_VERY_HIGH;
    DMA_InitStructure.Mem2Mem        = DMA_M2M_DISABLE;
    DMA_Init(DMA_CH4, &DMA_InitStructure);
    DMA_RequestRemap(DMA_REMAP_USART1_TX, DMA, DMA_CH4, ENABLE);

    /* USARTy RX DMA Channel (triggered by USARTy Rx event) Config */
    DMA_DeInit(DMA_CH5);
    DMA_InitStructure.PeriphAddr     = (USART1_BASE + 0x04);
    DMA_InitStructure.MemAddr        = (uint32_t)g_USART1ReadDMABuff;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_SRC;
    DMA_InitStructure.BufSize        = USART1_DMA_READ_LENGTH;
    DMA_InitStructure.CircularMode   = DMA_MODE_CIRCULAR;
    DMA_Init(DMA_CH5, &DMA_InitStructure);
    DMA_RequestRemap(DMA_REMAP_USART1_RX, DMA, DMA_CH5, ENABLE);


    /* Enable USARTy DMA Rx and TX request */
    USART_EnableDMA(USART1, USART_DMAREQ_RX | USART_DMAREQ_TX, ENABLE);

    /* Enable USARTy TX DMA Channel */
    DMA_EnableChannel(DMA_CH4, ENABLE);
    /* Enable USARTy RX DMA Channel */
    DMA_EnableChannel(DMA_CH5, ENABLE);
}


void vUart2Init(void)
{
    GPIO_InitType GPIO_InitStructure = {0};
    USART_InitType USART_InitStructure = {0};
    NVIC_InitType NVIC_InitStructure = {0};


    /* Enable GPIO clock */
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
    /* Enable USARTx Clock */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_USART2, ENABLE);


    /* Configure USARTy Tx as alternate function push-pull */
    GPIO_InitStructure.Pin            = GPIO_PIN_2;
    GPIO_InitStructure.GPIO_Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStructure.GPIO_Alternate = GPIO_AF4_USART2;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);

    /* Configure USARTx Rx as alternate function push-pull */
    GPIO_InitStructure.Pin            = GPIO_PIN_3;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);


    /* USARTx configuration ------------------------------------------------------*/
    USART_InitStructure.BaudRate            = 115200;
    USART_InitStructure.WordLength          = USART_WL_8B;
    USART_InitStructure.StopBits            = USART_STPB_1;
    USART_InitStructure.Parity              = USART_PE_NO;
    USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
    USART_InitStructure.Mode                = USART_MODE_RX | USART_MODE_TX;
    USART_Init(USART2, &USART_InitStructure);


    vUart2DMAInit();


    /* Enable the USARTx Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel            = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPriority    = 3;
    NVIC_InitStructure.NVIC_IRQChannelCmd         = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* Enable USARTx IDLE interrupts */
    USART_ConfigInt(USART2, USART_INT_IDLEF, ENABLE);


    /* Enable the USARTx */
    USART_Enable(USART2, ENABLE);
}

void vUart2DMAInit(void)
{
    DMA_InitType DMA_InitStructure = {0};


    /* DMA clock enable */
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE);


    /* USARTy TX DMA Channel (triggered by USARTy Tx event) Config */
    DMA_DeInit(DMA_CH3);
    DMA_InitStructure.PeriphAddr     = (USART2_BASE + 0x04);
    DMA_InitStructure.MemAddr        = (uint32_t)g_USART2SendDMABuff;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_DST;
    DMA_InitStructure.BufSize        = USART2_DMA_SEND_LENGTH;
    DMA_InitStructure.PeriphInc      = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.DMA_MemoryInc  = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
    DMA_InitStructure.MemDataSize    = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.CircularMode   = DMA_MODE_NORMAL;
    DMA_InitStructure.Priority       = DMA_PRIORITY_VERY_HIGH;
    DMA_InitStructure.Mem2Mem        = DMA_M2M_DISABLE;
    DMA_Init(DMA_CH3, &DMA_InitStructure);
    DMA_RequestRemap(DMA_REMAP_USART2_TX, DMA, DMA_CH3, ENABLE);

    /* USARTy RX DMA Channel (triggered by USARTy Rx event) Config */
    DMA_DeInit(DMA_CH2);
    DMA_InitStructure.PeriphAddr     = (USART2_BASE + 0x04);
    DMA_InitStructure.MemAddr        = (uint32_t)g_USART2ReadDMABuff;
    DMA_InitStructure.Direction      = DMA_DIR_PERIPH_SRC;
    DMA_InitStructure.BufSize        = USART2_DMA_READ_LENGTH;
    DMA_InitStructure.CircularMode   = DMA_MODE_CIRCULAR;
    DMA_Init(DMA_CH2, &DMA_InitStructure);
    DMA_RequestRemap(DMA_REMAP_USART2_RX, DMA, DMA_CH2, ENABLE);


    /* Enable USARTy DMA Rx and TX request */
    USART_EnableDMA(USART2, USART_DMAREQ_RX | USART_DMAREQ_TX, ENABLE);

    /* Enable USARTy TX DMA Channel */
    DMA_EnableChannel(DMA_CH3, ENABLE);
    /* Enable USARTy RX DMA Channel */
    DMA_EnableChannel(DMA_CH2, ENABLE);
}


void vUartSendDatas(USART_Module* USARTx, uint8_t *pucDatas, int32_t iLength)
{
    uint32_t uiTime = 0;

    while((iLength--) > 0)
    {
        uiTime = 1000;
        while((RESET == USART_GetFlagStatus(USARTx, USART_FLAG_TXDE)) && (--uiTime));

        /* Transmit Data */
        USARTx->DAT = *pucDatas++;
    }
}

void vUartSendStrings(USART_Module* USARTx, char *pcStrings)
{
    vUartSendDatas(USARTx, (uint8_t *)pcStrings, strlen(pcStrings));
}


/**
 * @brief  设置DMA的数据传输长度，并启动DMA传输
 * @param  DMAy_Channelx：   相应DMA的通道
           Length：          传输长度
 * @retval 无
 */
void vDMASetAddrAndLenthStart(DMA_ChannelType *channelx, uint32_t uiSourceAddress, uint32_t uiTargetAddress, uint32_t uiLength)
{
    uint32_t uiTime = 0;

    uiTime = 1000000;
    /* Disable the peripheral */
    DMA_EnableChannel(channelx, DISABLE);
    while(((channelx->CHCFG & DMA_CHCFG1_CHEN) != 0) && (--uiTime));

    /* 必须要清除所有中断状态，才允许使能DMA */
    DMA_ClearFlag(0xFFFFFFFF, DMA);

    /* Write to DMAy Channelx MADDR */
    channelx->MADDR = uiSourceAddress;

    /* Write to DMAy Channelx PADDR */
    channelx->PADDR = uiTargetAddress;

    /* Write to DMA Channelx TXNUM */
    channelx->TXNUM = uiLength;

    uiTime = 1000000;
    /* Enable the Peripheral */
    DMA_EnableChannel(channelx, ENABLE);
    while(((channelx->CHCFG & DMA_CHCFG1_CHEN) == 0) && (--uiTime));
}

void vUartDMASendDatas(USART_Module* USARTx, uint8_t *pucDatas, int32_t iLength)
{
    DMA_ChannelType* enumChannelx = DMA_CH4;
    uint32_t uiFlagStatus = 0;
    int32_t iDMAMaxLength = 0;
    uint8_t *pucSendDatasHandle = pucDatas;

    if(iLength <= 0)
        return;

    switch((uint32_t)USARTx)
    {
        case (uint32_t)USART1: enumChannelx = DMA_CH4; uiFlagStatus = DMA_FLAG_TC4; pucSendDatasHandle = g_USART1SendDMABuff; iDMAMaxLength = USART1_DMA_SEND_LENGTH; break;
        case (uint32_t)USART2: enumChannelx = DMA_CH3; uiFlagStatus = DMA_FLAG_TC3; pucSendDatasHandle = g_USART2SendDMABuff; iDMAMaxLength = USART2_DMA_SEND_LENGTH; break;

        default : printf("vUartDMASendDatas channel error.\r\n"); return;
    }

    /* 等待上次DMA传输完成 */
    while((DMA_GetFlagStatus(uiFlagStatus, DMA) == RESET) && ((enumChannelx->CHCFG & DMA_CHCFG1_CHEN) != 0));

    /* 方式1：充分利用DMA不占用CPU的时间 */
    if(iLength <= iDMAMaxLength)
    {
        memcpy(pucSendDatasHandle, pucDatas, iLength);

        /* 设置传输地址与长度，并启动DMA发送 */
        vDMASetAddrAndLenthStart(enumChannelx, (uint32_t)pucSendDatasHandle, (uint32_t)(&(USARTx->DAT)), iLength);
    }
    /* 方式2：发送后再等待，防止发送的数据缓存被之后的代码更改 */
    else
    {
        /* 设置传输地址与长度，并启动DMA发送 */
        vDMASetAddrAndLenthStart(enumChannelx, (uint32_t)pucDatas, (uint32_t)(&(USARTx->DAT)), iLength);

        /* 等待本次DMA传输完成 */
        while(DMA_GetFlagStatus(uiFlagStatus, DMA) == RESET);
    }
}

void vUartDMASendStrings(USART_Module* USARTx, char *pcStrings)
{
    vUartDMASendDatas(USARTx, (uint8_t *)pcStrings, strlen(pcStrings));
}
